package top.whysu.gps.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.security.MessageDigest;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Pattern;


/**
 * 密码校验及生成工具类
 *
 * @author chenjinlu
 */
public class PwdTool {

    /**
     * 校验动态密码
     *
     * @param pwd
     * @return
     */
    public static boolean verifySupperPwd(String pwd, String key) {
        boolean result = false;
        byte[] num = null;
        num = StringToBytes(key);
        if (StringUtils.isEmpty(pwd)) return result;

        Date dNow = new Date();
        Date dBefore = dateForwardHalfHour(dNow);
        Date dAfter = dateBackwardHalfHour(dNow);
        //校验密码
        try {
            String pwd1 = calcSuperPwd(num, dateToBytes(dBefore, 16));
            String pwd2 = calcSuperPwd(num, dateToBytes(dAfter, 16));

            //匹配
            if (pwd.equals(pwd1) || pwd.equals(pwd2)) {
                result = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 计算动态密码
     *
     * @param num
     * @param time
     * @return
     * @throws Exception
     */
    public static String calcSuperPwd(byte[] num, byte[] time) throws Exception {
        if (num == null || num.length != 6 || time == null || time.length != 6) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        byte[] temp = new byte[6];
        String strMd5 = "";

        //计算

        byte[] xor = {0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC};
        byte[] sum = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
        for (int i = 0; i < 6; i++) {
            temp[i] = (byte) (num[i] ^ xor[i] + time[i] + sum[i]);
        }
        //计算MD5
        try {
            strMd5 = encryptMD5(temp);
        } catch (Exception e) {
            throw new Exception("To calculate the MD5 value fails");
        }

        //取MD5后8位
        strMd5 = strMd5.substring(strMd5.length() - 8);
        byte[] result = strMd5.getBytes();

        //对10取余
        for (int i = 0; i < result.length; i++) {
            sb.append(result[i] % 10);
        }
        return sb.toString();
    }

    /**
     * 计算MD5值
     *
     * @param str
     * @return
     * @throws Exception
     */
    public static String encryptMD5(byte[] str) throws Exception {
        MessageDigest messageDigest = null;

        messageDigest = MessageDigest.getInstance("MD5");

        messageDigest.reset();

        messageDigest.update(str);

        byte[] byteArray = messageDigest.digest();

        StringBuffer md5StrBuff = new StringBuffer();

        //拼接完整32位字符串
        for (byte b : byteArray) {
            md5StrBuff.append(String.format("%02x", b & 0xff));
        }

        return md5StrBuff.toString().toLowerCase(Locale.getDefault());
    }

    /**
     * 时间往后半小时并取整
     *
     * @param date
     * @return
     */
    public static Date dateForwardHalfHour(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, -30);

        int minute = calendar.get(Calendar.MINUTE);

        if (minute > 0 && minute < 30) {
            calendar.add(Calendar.HOUR, 1);
            calendar.set(Calendar.MINUTE, 0);
        } else if (minute > 30 && minute < 60) {
            calendar.add(Calendar.HOUR, 1);
            calendar.set(Calendar.MINUTE, 30);
        }

        return calendar.getTime();
    }

    /**
     * 时间往后一小时并取整
     *
     * @param date
     * @return
     */
    public static Date dateBackwardHalfHour(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, 30);

        int minute = calendar.get(Calendar.MINUTE);

        if (minute > 0 && minute < 30) {
            calendar.set(Calendar.MINUTE, 30);
        } else if (minute > 30 && minute < 60) {
            calendar.add(Calendar.HOUR, 1);
            calendar.set(Calendar.MINUTE, 0);
        }

        return calendar.getTime();
    }

    /**
     * 日期转byte数组
     *
     * @param date
     * @param radix 进制
     * @return
     */
    public static byte[] dateToBytes(Date date, int radix) {
        String format = "yyyyMMddHHmm";
        byte[] result = new byte[6];
        String str = DateFormatUtils.format(date, format);
        for (int j = 0, i = 0; i < format.length(); j++) {
            result[j] = (byte) Integer.parseInt(str.substring(i, i + 2), radix);
            i += 2;
        }
        return result;
    }

    /**
     * 字符串转byte[]
     *
     * @return
     */
    public static byte[] StringToBytes(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }

        String[] strs = str.split("");

        if (strs.length != 6) {
            return null;
        }
        byte[] bytes = new byte[6];
        for (int i = 0; i < 6; i++) {
            bytes[i] = (byte) Integer.parseInt(strs[i], 16);
        }
        return bytes;
    }

    public static Boolean validatePwd(String pwd) {
        String pattern = "^[A-Za-z0-9]+$";
        Boolean isMatch = Pattern.matches(pattern, pwd);
        return isMatch;
    }

}
